CS 454/554 Homework 3, Due on: February 27, 2001, before class

 

Execute the C programs given in the following problems. Observe and interpret the results. You will learn about UNIX by performing the suggested experiments. The information given at the end is useful in interpreting some of the results. You are allowed to work on this project as a group project. You will have to choose your own group and you can have at the most two members in a group. Only one answer should be submitted for each group. List the names of all group members on the answers sheet.

 

Although you may work as a group, each member is expected to learn about all the problems. This is assigned as a group project to enrich your learning experience through discussions among the group. If you share the work, make sure that you have discussions among the group members so that every member gets all the information about work done by others. Ultimately you will have to work on similar problems on a test.

 

Note: The problems, marked by "*" are only for CS554.

Submission: The answer for each problem should be provided in the following format:

 

(a) description of the observed results, (b) explanation of observed results. In addition to answers for individual questions write a one paragraph summary of your learning experience through this homework. The summary must be typed on a separate page. Staple the pages together in the following order: (I) Cover sheet, (II) Summary page, (III) the answers for individual problems.

Important: Follow the submission instructions, otherwise you may loose points.

 

This assignment has two parts. 

Part 1: Learning about UNIX processes and 

Part 2: Learning about UNIX Inter Process Communication (IPC)

 

 

Part I

Learning About UNIX Processes 

 

UNIX Calls used in the following problems: getpid(), getppid(), sleep(), fork(), and wait(). Use the on-line help or a UNIX book for further information on UNIX calls.

 

1. Run the following program twice. Both times as a background process, i.e. suffix it with an ampersand. Once both processes are running as background processes, view the process table (Use ps -el UNIX command). Observe the process state, PID (process ID) etc. Repeat this experiment to observe the changes, if any.

main() {

    printf("Process ID is: %d\n", getpid());

    printf("Parent process ID is: %d\n", getppid());

    sleep(120);

    printf("I am awake. \n");

}

 

 

2. Run the following program and observe the number of times and the order in which the print statement is executed. The fork() creates a child that is a duplicate of the parent process. The child process begins from the fork(). All the statements after the call to fork() are executed by the parent process and also the child process. Draw a family tree of processes and explain the results you observed.

main(){

fork();

fork();

printf("Parent Process ID is %d\n", getppid());

}

 

3. Run the following program and observe the output. In UNIX, fork() returns the value of the child's PID to the parent process and zero value to the child process.

main() {

int pid;

pid = fork();

if (pid == 0) {

printf("The child process ID is %d\n", getpid());

printf("The child's parent process ID is %d\n", getppid());

}

else {

printf("The parent process ID is %d\n", getpid());

printf("The parent's parent process ID is %d\n", getppid());

}

}

 

4. Run the following program observe the result of time slicing used by UNIX .

 

main() {

int i=0,j=0,pid;

pid = fork();

if (pid == 0) {

    for(i=0;i<500;i++)

    printf("Child: %d\n",i);

}

else {

    for(j=0;j<500;j++)

        printf("Parent: %d\n",j);

}

}

 

5. Run the following program and observe the result of synchronization using the wait().

main()

    int i=0,j=0,pid;

    pid = fork();

if (pid == 0) {

    for(i=0;i<500;i++)

        printf("Child: %d\n",i);

    printf("Child ends\n");

}

else {

wait(0);

printf("Parent resumes. \n");

for(j=0;j<500;j++)

    printf("Parent: %d\n",j);

}

}

 

*6. The UNIX provides the exec() family of calls which allows one to build a system using small programs that handle only one task. These in turn can call others. We can have a synergy of small processes that come to life, execute, and are born again with a different purpose. The exec() creates a new process that overwrites in the parent process's memory space. The new process has the same PID, current directory etc. Design a couple of experiments to learn more about the execl() call and how it differs from the fork() call.

 

Part II

Learning About Inter Process Communication in UNIX

 

 

Execute the C programs given in the following problems. Observe and Interpret the results. You will learn about some of the different ways of communication between UNIX processes by performing the suggested experiments. Some of the problems, marked by "*", are optional for CS454. The CS554 students should do all the problems.

 

Some of the UNIX calls used in the following problems are: signal(), sigkey(), exit(), alarm(), pipe(), mknod() and perror(). Use the on-line help or a UNIX book for further information on UNIX calls.

Submission: The answer for each problem should be provided in the following format:

(a) a report of your observations, (b) an explanation of observed results. In addition to answers for individual questions write a cohesive summary of what you have learnt through the various experiments done as a part of this homework. The summary must be typed on a separate sheet of paper. Staple the pages together in the following order: (I) Cover sheet, (II) Summary sheet(s), (III) the answers for individual problems. 

 

1. The objective of this exercise is to introduce signals. Execute the following program and its suggested modifications. Observe and interpret the results. 

#include <signal.h>

void my_routine( );

main( )                                                                     void my_routine( )

{                                                                           {

    printf(" Press <DEL> key.\n");                                             printf(" Have a good day ! \n");

    signal(SIGINT, my_routine);                                             }

    for( ; ; );

}

Modifications: (I) Press the delete key twice. What happens the second time? Why? (II) Omit the signal( ) statement in the main program, run the program, observe the result. (III) Add the statement signal(SIGINT, my_routine) after the print statement in the my_routine( ). Run the program and observe results. Relate the three parts and explain their results in one cohesive way. (IV) In main( ), replace the signal( ) statement by: signal(SIGINT, SIG_IGN); Observe the result and explain what happens. If you get stuck, you can kill processes by pressing CTRL \. (V) The signal sent when CTRL \ is pressed is SIGQUIT and the name of the signal service routine is sigkey( ); Go back to the original code. Change the name my_routine to sigkey and observe what happens when you press CTRL \.

 

2. Run the following program. Design some experiments. Describe your experiments, state results

and explain them.

#include <signal.h>

void my_routine( );

main( )                                                                          void my_routine(signo )

{                                                                                {

signal(SIGINT, my_routine);                                                         printf(" The signal number is %d\n", signo);

signal(SIGQUIT, my_routine);                                                     }

for( ; ; );

}

 

 

3. Figure out what this program does and explain it.

#include <signal.h>

#include <stdio.h>

char msg[100];

main(argc,argv)                                                                 void my_secretary ( )

int argc;                                                                       {

char *argv[ ];                                                                       printf("%s\n",msg);

{                                                                                    exit(0);

int time;                                                                   }

void my_secretary( );

time = atoi(argv[2]);

strcpy(msg, argv{1});

signal(SIGALRM, my_secretary);

alarm(time);

for( ; ;);

}

Comment: A Unix pipe is a one way communication channel. A pipe is used to pass a character stream from one process to another. Some of the commonly used examples of pipes are: cat <file name> | more, who | wc -l. The pipe(p) (p is declared as int p[2];) commands opens the pipe. The command returns two file descriptors p[0] ( the read end) and p[1] ( the write end). These file descriptors are common to all processes. Therefore, there is a limit to how many pipes can be there one time.

 

4. Observe the output and explain.

#Include <stdio.h>                                                                 

#define MSGSIZE 16                                                                    

main( )                                                                            

{                                                                                       

char *msg1 = " How are you ?";                                                     

char inbuff[MSGSIZE];                                                              

int p[2], pid;                                                                

pipe(p);                                                                      

pid = fork( );

if (pid > 0)

     write(p[1],msg1,MSGSIZE);

else{

    sleep(1);

    read(p[0],inbuff,MSGSIZE);

    printf("%s\n",inbuff); 

exit(0);

}